/* Copyright  2009-2010
   @Author
   Richard Changde Yin            e-mail yinchangde@hotmail.com

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/**
 * @filename: catalogtable.h
 */

#ifndef __CATALOGTABLE_H__
#define __CATALOGTABLE_H__

#include <common.h>
#include <os.h>
#include <index.h>
#include <debug.h>
#include <util.h>

#include <thr_lock.h>

extern char ChunkName[MAX_CHUNKS][CHUNK_NAME_LEN];



class ChunkIterator;

enum CatalogTableID
{
    // chunk id 0 ->userChunkTable
    //
    // chunk id 10->DATABASE
    // chunk id 11->USER
    // chunk id 12->TABLE
    // chunk id 13->FIELD
    // chunk id 14->ACCESS
    // chunk id 15->INDEX
    // chunk id 16->INDEXFIELD

    UserChunkTableId      =  0,
    LockTableHashBucketId =  1,
    LockTableMutexId      =  2,
    LockTableId           =  3,
    TransHasTableId       =  4,
    UndoLogTableID        =  5,


    DatabaseTableId       = 10,
    UserTableId           = 11,
    TableTableId          = 12,
    FieldTableId          = 13,
    AccessTableId         = 14,
    IndexTableId          = 15,
    IndexFieldTableId     = 16,
    TmpTableTableId       = 17,
    UserIndexChunkId      = 18

};
enum  TABLETYPE {

    NORMAL_TYPE   = 1 ,
    INTERNAL_TYPE = 2 ,
    TEMP_TYPE
};
/* m_ctype.h*/
typedef struct charset_info_st CHARSET_INFO;

class CTABLE
{
    CTABLE& operator = (CTABLE& table);
    CTABLE (CTABLE&);
    CTABLE (const CTABLE&);
public:
    CTABLE():index_length(0),
                keys(0),
                currently_disabled_keys(0),
                reclength(0),
                tbl_type(NORMAL_TYPE)
    {
      table_charset = 0;
    }

    inline void init(){
      index_length=0;
      keys=0;
      currently_disabled_keys=0;
      reclength=0;
      tbl_type=NORMAL_TYPE;
      bzero(tblName_,IDENTIFIER_LENGTH);
      bzero(tblowner,IDENTIFIER_LENGTH);
      fixed_data_length =0 ;
      fixed_column_count = 0;
      table_charset = 0;
      tblID_        = 0;
      auto_key      = 0 ;
      auto_key_offset=0;
    }

    inline void initLock()
    {
      thr_lock_init(&lock);
      pthread_mutex_init(&intern_lock,MY_MUTEX_INIT_FAST);
      pthread_mutex_init(&auto_inc_lock,MY_MUTEX_INIT_FAST);
    }

    inline void destoryLock()
    {
      thr_lock_delete(&lock);
      pthread_mutex_destroy(&intern_lock);
      pthread_mutex_destroy(&auto_inc_lock);
    }
    char      tblName_[IDENTIFIER_LENGTH];
    char      tblowner[IDENTIFIER_LENGTH];
    const     CHARSET_INFO *  table_charset;
    void*     tblID_     ;
    ///length of the tuple
    size_t    length_of_tuple    ;
    int32_t   numFlds_   ;
    int32_t   numIndexes_;
    void*     chunkPtr_  ;

    ///  table name string length
    size_t   namelength ;
    uint64_t index_length    ;
    uint32_t key_stat_version;
    uint32_t keys            ;
    uint32_t currently_disabled_keys;  /* saved value from "keys" when disabled */
    uint32_t reclength;
    uint32_t fixed_data_length; /* Length of record's fixed part, which contains keys and always fits into the first chunk */
    uint32_t fixed_column_count;/* Number of columns stored in fixed_data_length */
    TABLETYPE tbl_type ;
    uint64_t auto_increment;
    THR_LOCK lock;
    pthread_mutex_t intern_lock;
    pthread_mutex_t auto_inc_lock;
    uint32_t auto_key;
    uint32_t auto_key_type;
    uint32_t auto_key_offset;
};

class CatalogTableTABLE
{
    Database *systemDatabase_;
    CatalogTableTABLE();
    CatalogTableTABLE& operator=(CatalogTableTABLE&);
    CatalogTableTABLE(CatalogTableTABLE&);
public:
    CatalogTableTABLE(Database *db_):systemDatabase_ (db_)
                                    {}

    //void* tptr is OUT parameter which will contain the
    //pointer to the inserted CatalogTableTABLE
    BackEnd::DbRetVal insert(const char *name,
                                 int64_t id,
                                 size_t  size,
                                 int32_t numFlds,
                                 void*   chunk,
                                 void *& tptr,
                                 int32_t _namelen,
                                 HA_CREATE_INFO* create_info,
                                 TABLETYPE = NORMAL_TYPE );

    //Second argument is OUT parameter which will contain the
    //chunk pointer of this table
    //Third argument is OUT parameter which will contain the
    //pointer to the removed tuple
    BackEnd::DbRetVal remove  (const char *name,
                               void *&chunk,
                               void *&tptr);
    BackEnd::DbRetVal getChunkAndTblPtr(const char *name,
                                        void *&chunk,
                                        void *&tptr);

};


class CFIELD
{
public:

    char fldName_[IDENTIFIER_LENGTH];
    const     CHARSET_INFO *    charset      ;
    void*  tblID_;      //table id where this field resides
    void* tblPtr_;    //pointer to tuple in catalog table TABLE
    //DataType type_;
    enum_field_types type_ ;     /* en_fieldtype */
    size_t  length_;  //length of the field
    size_t  offset_;  //offset (in bytes) into tuple
    //currently default value is supported for string and binary
    //less than length 32 bytes
    char defaultValueBuf_[DEFAULT_VALUE_BUF_LENGTH];
    bool isNull_   ;
    bool isPrimary_;
    bool isUnique_ ;
    bool isDefault_;

    uint16_t null_pos;       /* position for null marker */
    uint8_t  null_bit;       /* If column may be 0 */
    uint8_t  length_bytes;  /* length of the size, 1 o 2 bytes */
    /* TODO:*/
    int32_t width_;
    int32_t scale_;

    uint32_t  fldNameRealLen ;
};

class CatalogTableFIELD
{
    Database *systemDatabase_;
public:
    CatalogTableFIELD(Database *db):systemDatabase_(db) { }

    //returns -1 on error

    BackEnd::DbRetVal insert(Table&tbl,int tblID, void *tblPtr);

    BackEnd::DbRetVal insert(Table&tbl,int tblID, void *tblPtr, char **& out_fptr);

    BackEnd::DbRetVal remove(void *tblPtr);

    //II argument is OUT parameter
    //field list is populated from the catalog table for
    // the table pointed by tblPtr
    //void getFieldInfo( void* tblPtr, M_FieldList &list);
    /*
    //array is OUT param
    //returns the pointer to fields for the corresponding name
    //in field name list as an array*/
    BackEnd::DbRetVal getFieldPtrs(const char* fldname ,
                                   void *tptr,
                                   char **&array);

};
/*
class CUSER
{
    public:
    char userName_[IDENTIFIER_LENGTH];
    char password_[IDENTIFIER_LENGTH];
};
*/
class CatalogTableUSER
{
    Database *systemDatabase_;
public:
    CatalogTableUSER(Database *db_):systemDatabase_(db_){}

    //returns -1 on error
    BackEnd::DbRetVal insert(const char *name, const char *pass);
    /*
    DbRetVal authenticate(const char *name, const char *pass,
                     bool &isAuthenticated, bool &isDba);
    */
    BackEnd::DbRetVal remove(const char *name);
    /*
    DbRetVal changePass(const char *name, const char *pass);
    */
};

class CACCESS
{
public:
    char userName_[IDENTIFIER_LENGTH];
    char dbName_  [IDENTIFIER_LENGTH];
};

class CDATABASEFILE
{
public:
    int     dbID_;
    char    dbName_[IDENTIFIER_LENGTH];
    int     maxChunks_;
    size_t  maxSize_;  //maximum size of database
    caddr_t dbStart_; //address where the database is mapped
};

class CINDEX
{
    CINDEX& operator= (CINDEX& idx);
    CINDEX (CINDEX& idx);
    CINDEX (const CINDEX& idx);
public:
    CINDEX():charset(0),
             tblPtr_(0),
             chunkPtr_(0),
             hashNodeChunk_(0),
             fstIndFld_(0),
             fldOffset(UINT_MAX)
    {
      bzero(indName_,sizeof(indName_));
    }

    inline void init(){
      bzero(indName_,sizeof(indName_));
      charset=0;
      tblPtr_=0;
      chunkPtr_=0;
      hashNodeChunk_=0;
      fstIndFld_=0;
      fldOffset=UINT_MAX;
    }
    char      indName_[IDENTIFIER_LENGTH];
    const     CHARSET_INFO *    charset;
    int32_t   tblID_;      //table id of the table
    //pointer to tuple in catalog table TABLE
    void*     tblPtr_;
    /*enum IndexType  declared index.h*/
    IndexType indexType_;
    //pointer to the index chunk
    void*     chunkPtr_;
    int32_t   numFlds_;
    int32_t   noOfBuckets_;
    bool      isUnique_;
    bool      isPrimary;
    void *    hashNodeChunk_;
    void *    fstIndFld_;//pointer to fisrt index field

    uint      fldOffset ;

    uint32_t  flag;             /* HA_NOSAME | HA_NULL_PART_KEY */
    uint32_t  start;            /* Start of key in record */
    uint32_t  null_pos;         /* position to NULL indicator */
    uint16_t  bit_pos;          /* Position to bit part */
    uint16_t  length;           /* Keylength */

};

class CatalogTableINDEX
{
    Database *systemDatabase_;
    CatalogTableINDEX& operator= (CatalogTableINDEX& );
    CatalogTableINDEX(const CatalogTableINDEX&);
public:
    CatalogTableINDEX(Database *db):systemDatabase_ (db){}


    //tupleptr is OUT parameter which will give the pointer to
    //the index tuple
    BackEnd::DbRetVal insert(const char *name,
                             void *tblPtr,
                             int32_t numFlds,
                             bool  isUnique,
                             void* chunk,
                             int32_t bucketSize,
                             void *hChunk,
                             void *&tupleptr,
                             /*default is HASH IDX Type*/
                             IndexType _idxtype = hashIndex);

    BackEnd::DbRetVal insert(const char *name,
                             void *tblPtr,
                             IndexInfo* idxinfo,
                             void* chunk,
                             void *hChunk,
                             void *&tupleptr);

    //Second argument is OUT parameter which will contain the
    //chunk pointer of this table
    //Third argument is OUT parameter which will contain the
    //pointer to the removed tuple
    BackEnd::DbRetVal remove(const char *name,
                             void* tptr ,
                             void *&chunk,
                             void *&hchunk,
                             void *&iptr);

    BackEnd::DbRetVal get   (const char *name,
                             void *&chunk,
                             void *&hchunk,
                             void *&iptr);

    //get the number of indexes on table pointed by tblPtr
    uint32_t   getNumIndexes(void *tblPtr);

    char*   getIndexName (void *tblPtr, int32_t pos);

    CINDEX* getIndexPtrByName(void *tptr, const char* idxname);
    //gets all the index ptrs as array for the table pointed by tblPtr
    void getIndexPtrs(void *tblPtr, char **&array);

    static ChunkIterator getIterator(void *iptr) ;
    static int   getNoOfBuckets(void *iptr);
    static int   getUnique(void *iptr);
    static char* getName  (void *iptr);
};


class CINDEXFIELD
{
public:
    void* indexPtr; //pointer to tuple in catalog table INDEX
    void* tablePtr; //pointer to tuple in catalog table TABLE
    void* fieldPtr; //pointer to tuple in catalog table FIELD
    CINDEXFIELD *next;
};

#endif /*__CATALOGTABLE_H__*/
